package com.qen.encrypt.configuration;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.qen.encrypt.inter.ApiResponse;
import com.qen.encrypt.inter.Encrypt;
import com.qen.encrypt.inter.EncryptGroup;
import com.qen.encrypt.properties.EncryptMapConfig;
import com.qen.encrypt.utils.ParamEncrypt;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * 对响应内容进行加密
 */
@ControllerAdvice
public class EncryptResponse implements ResponseBodyAdvice<ApiResponse> {
    private EncryptMapConfig encryptMapConfig;

    public EncryptResponse(@Qualifier("encryptMapConfig") EncryptMapConfig encryptMapConfig) {
        this.encryptMapConfig = encryptMapConfig;
    }

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return returnType.hasMethodAnnotation(Encrypt.class);
    }

    @Override
    public ApiResponse beforeBodyWrite(ApiResponse body, MethodParameter parameter, MediaType selectedContentType,
                                       Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
                                       ServerHttpResponse response) {
        try {
            if (body.getCode() != 200) {
                return body;
            }
            ParamEncrypt encrypt = getGroupKey(parameter);
            String[] keys = parameter.getMethodAnnotation(Encrypt.class).value();
            if (keys != null) {
                for (String key : keys) {
                    if (ApiResponse.DEFAULT_DATA.equals(key) || ApiResponse.DEFAULT_MESSAGE.equals(key)) {
                        continue;
                    }
                    String old = JSONObject.toJSONString(body.get(key));
                    body.put(key, encrypt.pubEncrypt(old));
                }
            }
            if (body.getMessage() != null) {
                body.setMessage(encrypt.pubEncrypt(body.getMessage()));
            }
            if (body.getData() != null) {
                body.setData(encrypt.pubEncrypt(JSONObject.toJSONString(body.getData())));
            }
            body.setEncrypt(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return body;
    }

    private ParamEncrypt getGroupKey(MethodParameter parameter) {
        Class<?> declared = parameter.getMethod().getDeclaringClass();
        if (parameter.hasMethodAnnotation(EncryptGroup.class)) {
            String methodGroup = parameter.getMethodAnnotation(EncryptGroup.class).value();
            if (StrUtil.isNotBlank(methodGroup)) {
                return encryptMapConfig.getParamEncrypt(methodGroup);
            } else {
                return encryptMapConfig.getParamEncrypt();
            }
        } else if (declared.isAnnotationPresent(EncryptGroup.class)) {
            String group = declared.getAnnotation(EncryptGroup.class).value();
            if (StrUtil.isNotBlank(group)) {
                return encryptMapConfig.getParamEncrypt(group);
            } else {
                return encryptMapConfig.getParamEncrypt();
            }
        }
        return encryptMapConfig.getParamEncrypt();
    }
}
